using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace WbsEditor.Generation
{
    public partial class IterationWorkloadChartDialog : Form
    {
        public IterationWorkloadChartDialog(WorkPackageInfo[] infos, WbsCanvas baseCanvas, WbsGenerator generator)
        {
            _infos = infos;
            _baseCanvas = baseCanvas;
            _generator = generator;
            InitializeComponent();
        }

        private WorkPackageInfo[] _infos;
        private WbsCanvas _baseCanvas;
        private WbsGenerator _generator;

        private void IterationWorkloadChartDialog_Load(object sender, EventArgs e)
        {
            InitChart();
        }

        private void InitChart()
        {
            // Extract workload data on the fly.
            _generator.GenerateWorkloadData(_infos);

            Dictionary<string, PersonConceptWorkload> conceptWorkload = 
                new Dictionary<string, PersonConceptWorkload>();

            List<string> names = new List<string>();
            CreateStubWorkloadForAllPersons(conceptWorkload, names);

            foreach (WorkPackageInfo info in _infos)
            {
                foreach (PersonWorkload work in info.WorkloadInfo)
                {
                    PersonConceptWorkload pcw = conceptWorkload[work.Name];
                    RemainingCompletedWork rcw = new RemainingCompletedWork(work.RemainingWork, work.CompletedWork);
                    pcw.SetWorkloadForConceptId(info.SeriesId, rcw);
                }
            }

            List<PersonConceptWorkload> workloads = new List<PersonConceptWorkload>();
            foreach (string name in names)
            {
                workloads.Add(conceptWorkload[name]);
            }

            _chart.Series.Clear();
            for (int i = 0; i<_infos.Length; ++i)
            {
                WorkPackageInfo info = _infos[i];
                bool isLastSeries = (i == _infos.Length - 1);
                Series series = new Series();
                if (info.Type == WorkPackageInfo.WorkPackageType.WorkBreakdownStructure)
                {
                    series.Name = string.IsNullOrEmpty(info.WorkBreakdownStructure.TID) ? info.WorkBreakdownStructure.Root.Title :
                        info.WorkBreakdownStructure.TID + " - " + info.WorkBreakdownStructure.Root.Title;
                }
                else if (info.Type == WorkPackageInfo.WorkPackageType.OrphanTasks)
                {
                    series.Name = "Orphan Tasks in iteration";
                }
                else
                {
                    series.Name = "Bugs in iteration";
                }

                series.ChartType = SeriesChartType.StackedColumn;

                foreach (PersonConceptWorkload pcw in workloads)
                {
                    DataPoint dp;
                    if (pcw.HasWorkloadForConceptId(info.SeriesId))
                    {
                        RemainingCompletedWork work = pcw.GetWorkloadForConceptId(info.SeriesId);
                        float workToUse = work.Remaining;
                        dp = new DataPoint(0.0, (double)workToUse);
                        if (workToUse > 0.01f)
                        {
                            dp.Label = workToUse.ToString();
                            dp.Tag = info;
                        }
                    }
                    else
                    {
                        dp = new DataPoint();
                    }
                    dp.AxisLabel = pcw.Name;
                    series.Points.Add(dp);
                }

                _chart.Series.Add(series);
            }
        }

        private void CreateStubWorkloadForAllPersons(Dictionary<string, PersonConceptWorkload> conceptWorkload, List<string> names)
        {
            foreach (WorkPackageInfo info in _infos)
            {
                AddAllNamesToList(info.WorkloadInfo, names);
            }

            names.Sort();
            int personId = 0;
            foreach (string name in names)
            {
                PersonConceptWorkload workload = new PersonConceptWorkload(name, personId++);
                conceptWorkload[name] = workload;
            }
        }

        private void AddAllNamesToList(PersonWorkload[] personWorkload, List<string> names)
        {
            foreach (PersonWorkload workload in personWorkload)
            {
                if (!names.Contains(workload.Name))
                {
                    names.Add(workload.Name);
                }
            }
        }

        private DataPoint _lastHighlightedDataPoint;
        private void _chart_MouseMove(object sender, MouseEventArgs e)
        {
            HitTestResult result = _chart.HitTest(e.X, e.Y);

            if (null != _lastHighlightedDataPoint)
            {
                _lastHighlightedDataPoint.BackHatchStyle = ChartHatchStyle.None;
            }

            if (result.ChartElementType == ChartElementType.DataPoint ||
                result.ChartElementType == ChartElementType.DataPointLabel)
            {
                DataPoint dp = result.Series.Points[result.PointIndex];
                WorkPackageInfo info = (WorkPackageInfo)dp.Tag;
                if (null != info)
                {
                    this.Cursor = Cursors.Hand;
                    dp.BackHatchStyle = ChartHatchStyle.Percent25;
                    _lastHighlightedDataPoint = dp;
                }
            }
            else 
            {
                this.Cursor = Cursors.Default;
                _lastHighlightedDataPoint = null;
            }
        }

        private WorkPackageInfo _clickedInfo;
        private string _clickedName;

        private void _chart_MouseDown(object sender, MouseEventArgs e)
        {
            if (null == _lastHighlightedDataPoint)
                return;
            WorkPackageInfo info = (WorkPackageInfo)_lastHighlightedDataPoint.Tag;
            if (null == info)
                return;

            if (e.Button == MouseButtons.Left)
            {
                if (info.Type == WorkPackageInfo.WorkPackageType.WorkBreakdownStructure)
                {
                    DisplayWbsDialog(info);
                }
                else
                {
                    DisplayPersonalizedWbsDialog(_lastHighlightedDataPoint.AxisLabel);
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                _clickedInfo = info;
                _clickedName = _lastHighlightedDataPoint.AxisLabel;
                if (info.Type == WorkPackageInfo.WorkPackageType.WorkBreakdownStructure)
                {
                    _openWbsToolStripMenuItem.Visible = true;
                }
                else
                {
                    _openWbsToolStripMenuItem.Visible = false;
                }
                _dataPointMenu.Show(this, e.X, e.Y);
            }
        }

        private void DisplayWbsDialog(WorkPackageInfo info)
        {
            TempWbsDisplayDialog wbsDialog = new TempWbsDisplayDialog();
            WbsSettings settings = _baseCanvas.Settings.Clone();
            wbsDialog.WbsCanvas.Settings = settings;
            wbsDialog.WbsCanvas.TfsClient = _baseCanvas.TfsClient;
            settings.HighlightName = _lastHighlightedDataPoint.AxisLabel;
            try
            {
                wbsDialog.WbsCanvas.SetWorkBreakdownStructure(info.WorkBreakdownStructure);
                wbsDialog.WbsCanvas.ReadOnly = true;
                wbsDialog.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unhandled (but caught) exception:\n\n" + ex.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // Re-Init chart, values may have changed.
            InitChart();
        }

        private void _openWbsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (null == _clickedInfo)
                return;
            DisplayWbsDialog(_clickedInfo);
        }

        private void DisplayPersonalizedWbsDialog(string name)
        {
            TempWbsDisplayDialog wbsDialog = new TempWbsDisplayDialog();
            WbsSettings settings = _baseCanvas.Settings.Clone();
            settings.HighlightName = "";
            settings.CheckPlausis = false;
            settings.UseWbsCodes = false;
            wbsDialog.WbsCanvas.Settings = settings;
            wbsDialog.WbsCanvas.TfsClient = _baseCanvas.TfsClient;
            if (name.Equals("(unassigned)", StringComparison.CurrentCultureIgnoreCase))
            {
                name = "";
            }
            try
            {
                WorkBreakdownStructure wbs = _generator.GeneratePersonalizedWbsFromWorkPackageInfos(_infos, name);
                wbsDialog.WbsCanvas.SetWorkBreakdownStructure(wbs);
                wbsDialog.WbsCanvas.ReadOnly = true;
                wbsDialog.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unhandled (but caught) exception:\n\n" + ex.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // Re-Init chart, values may have changed.
            InitChart();
        }

        private void _openPersonalizedWbsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (null == _clickedName)
                return;
            DisplayPersonalizedWbsDialog(_clickedName);
        }
    }

    class RemainingCompletedWork
    {
        public RemainingCompletedWork(float remaining, float completed)
        {
            _remainingWork = remaining;
            _completedWork = completed;
        }
        private float _remainingWork;
        public float Remaining { get { return _remainingWork; } set { _remainingWork = value; } }

        private float _completedWork;
        public float Completed { get { return _completedWork; } set { _completedWork = value; } }

        public float Total { get { return Remaining + Completed; } }
    }

    class PersonConceptWorkload
    {
        public PersonConceptWorkload(string name, int id)
        {
            _name = name;
            _id = id;
        }
        private string _name;
        public string Name { get { return _name; } }

        private int _id;
        public int Id { get { return _id; } }

        private Dictionary<int, RemainingCompletedWork> _conceptWorkload = new Dictionary<int, RemainingCompletedWork>();
        public bool HasWorkloadForConceptId(int id)
        {
            return _conceptWorkload.ContainsKey(id);
        }

        public RemainingCompletedWork GetWorkloadForConceptId(int id)
        {
            return _conceptWorkload[id];
        }

        public void SetWorkloadForConceptId(int id, RemainingCompletedWork work)
        {
            _conceptWorkload[id] = work;
        }
    }
}